#pragma once

#include "VideoCapture.h"
#include "ffmpeg_headers.h"
#include <list>
#include "opencv2/opencv.hpp"

#include "ffmpeg_headers.h"
// 定义保存图像信息的结构体
struct ImageInfo {
	cv::Mat image;
	int width;
	int height;
};


class FFmpegVideoCapture :public VideoCapture, public MediaSourceEvent

{
public:

	FFmpegVideoCapture(const std::string& uri, const std::map<std::string, std::string>& opts = {});

	virtual ~FFmpegVideoCapture();

	/*VideoCapture callback*/
	virtual bool Start();

	virtual void Destroy();

	virtual void Stop(VideoYuvCallBack yuvCallback);

	virtual void Init(const char* devicename, int nWidth, int nHeight, int nFrameRate);
	
	virtual void Initdectect(const char* strJson) ;

	virtual void Init(std::map<std::string, std::string> opts = {});

	virtual void RegisterCallback(VideoYuvCallBack yuvCallback);

	virtual void RegisterH264Callback(H264CallBack h264Callback) { m_h264Callback = h264Callback; };

	virtual bool onData(const char* id, unsigned char* buffer, int size, int64_t ts);

	virtual bool onData(uint8_t* y, int strideY, uint8_t* u, int strideU, uint8_t* v, int strideV, int nWidth, int nHeight, int64_t nTimeStamp) ;

	virtual bool decodercallback(uint8_t* y, int strideY, uint8_t* u, int strideU, uint8_t* v, int strideV, int nWidth, int nHeight, int64_t nTimeStamp);

	virtual bool isDectect() 
	{ 
		
#ifdef USE_YOLO
		if (m_objectDectect.get() != nullptr)
		{
			return m_objectDectect->isdetector();
		}
		else
		{
			return false;
	}
	
#endif

		return false;
	};

	virtual	const Json::Value detectorinfo(const Json::Value& jmessage);
	
	virtual void stopDetector()
	{

#ifdef USE_YOLO
		if (m_objectDectect.get() != nullptr)
		{
			m_objectDectect->stopDetector();
		}

#endif

	};
	//开始编码线程
	void startEncoderThread();

	virtual bool isPlay() {

		if (m_h264Callback == nullptr)
		{
			return false;
		}
		else
		{
			return true;
		}

	}
	virtual void setCallbackEvent(MediaSourceEvent* callbackevent)
	{
		m_callbackEvent = callbackevent;
	};
public:

	bool  Initdecoder(const std::map<std::string, std::string>& opts);

	int calculateBitrate(int nWidth, int nHeight);

#ifdef USE_CUDA
	void InitCudaEncoder();
#endif // USE_CUDA

	void EncodecYUV(uint8_t* yuv, int nYUVLength, int nWidth, int nHeight);
public:
	virtual void OnSourceConnected(void* arg, const std::map<std::string, std::string>& opts)override;
	virtual bool onNewSession(const char* id, const char* media, const char* codec, const char* sdp, unsigned int rtpfrequency, unsigned int channels)override
	{
		if (m_callbackEvent)
		{
			m_callbackEvent->onNewSession(id, media, codec, sdp, rtpfrequency, channels);

		}
		return true;
	};
	virtual void OnSourceDisConnected(int err) override;
	virtual void OnSourceVideoPacket(const char* id, AVPacket* packet) override {};
	virtual void OnSourceAudioPacket(const char* id, AVPacket* packet)override {};
	virtual void OnSourceVideoPacket(const char* id, uint8_t* aBytes, int aSize, int64_t ts,bool bKey) override;
	virtual void OnSourceAudioPacket(const char* id, uint8_t* aBytes, int aSize, int64_t ts) override {};
	virtual bool OnIsQuitCapture() {
	
		if (m_bStop.load())
		{
			SPDLOG_LOGGER_ERROR(spdlogptr, "OnIsQuitCapture");
			return true;
		}
		return false; 
	};

private:

	std::list<VideoYuvCallBack> m_YuvCallbackList;
	std::atomic<bool>			m_bStop;
	std::mutex					m_mutex;                //互斥锁	
	H264CallBack				m_h264Callback;

	std::string				    m_videourl;
	std::map<std::string, std::string> m_codec;

	int							m_nWidth = 0, m_nHeight = 0;
	int							m_nFrameRate = 30;
	int m_nError = 0;	

	std::atomic<bool> m_useNullCodec;

	MediaSourceAPI*			 m_pSource = nullptr;
	FFmpegDecoderAPI*		 m_pDecoder = nullptr;
	FFmpegVideoEncoderAPI*	 m_ffmpegEncoder = nullptr;

	FFmpegAVFrameSWSAPI*	 m_FrameSWS = nullptr;
	char*					 m_pOutEncodeBuffer = nullptr;
	MediaSourceEvent* m_callbackEvent=nullptr;


	std::atomic<bool>	m_bKey;
	std::queue<ImageInfo> imageQueue;
	std::mutex queueMutex;
	std::condition_variable imageReady;

};

